//Place where I got the datepicker from
//http://grepcode.com/snapshot/repo1.maven.org/maven2/net.sourceforge.jdatepicker/jdatepicker/1.3.2
//Another source on how to use: http://stackoverflow.com/questions/8834207/why-do-the-date-pickers-trigger-a-jcomboboxs-actionperformed-unexpectedly
//http://sourceforge.net/projects/jdatepicker/

//Sample code for datepicker
/*
  protected JDatePickerImpl datePicker;
  //Needs to be an Object level variable
 
 	public void methodHeader(){
 		datePicker = (JDatePickerImpl) JDateComponentFactory.createJDatePicker();
		add(datePicker);	
		JButton buttonTest = new JButton("testing");	
		add (buttonTest);
		buttonTest.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				int day = datePicker.getModel().getDay();
				int month = datePicker.getModel().getMonth();
				int year = datePicker.getModel().getYear();
				//System.out.println(day + "" + month + "" + year);
				System.out.println("Day:" + day + " Month:" + ++month + " Year:" + year);
			}
		});
	}
 */

package com.livestocksolutions.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JSeparator;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.FontUIResource;

import com.livestocksolutions.Bovine;
import com.livestocksolutions.LivestockSolutions;
import com.livestocksolutions.util.JDatePickerDate;
import com.livestocksolutions.util.Logger;
import com.livestocksolutions.util.Table;

import java.awt.Dialog.ModalExclusionType;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.net.URL;
import java.util.Enumeration;

/**
 * The Main class where the Window is created.
 * @author Ken DeVries
 * @author Adam Parr
 * 
 * @.modified 6 March 2013
 */
public class MainFrame extends JFrame{
	private static final long serialVersionUID = 1L;
	
	/**
	 * The relative path to the Icon file to display in the main window.
	 */
	public static final String APP_ICON = "/images/livestocksolutions-white.png";
	/**
	 * The relative path to the Icon file to display in the Home tab.
	 */
	public static final String HOME_LIST = "/images/livestocksolutions-black.png";
	/**
	 * The relative path to the Icon file to display in the Cattle Tab
	 */
	public static final String CATTLE_LIST = "/images/cattle-black.png";
	/**
	 * The relative path to the Icon file to display in the Cattle Vet Visit Tab
	 */
	public static final String CATTLE_VET_VISIT_LIST = "/images/medical-black.png";
	/**
	 * The relative path to the Icon file to display in the Location Tab.
	 */
	public static final String LOCATION_LIST = "/images/location-black.png";
	/**
	 * The relative path to the Icon file to display in the Joining Tab.
	 */
	public static final String JOINING_LIST = "/images/join-black.png";
	/**
	 * The relative path to the Icon file to display in the Paddock Tab.
	 */
	public static final String PADDOCK_LIST = "/images/paddock-black.png";
	/**
	 * The relative path to the Icon file to display in the Medicine Tab.
	 */
	public static final String MEDICINE_LIST = "/images/medicine-black.png";
	/**
	 * The relative path to the Icon file to display in the Chemical Tab.
	 */
	public static final String CHEMICAL_LIST = "/images/chemical-black.png";
	/**
	 * The relative path to the Icon file to display in the Feed Tab.
	 */
	public static final String FEED_LIST = "/images/feed-black.png";
	/**
	 * The relative path to the Icon file to display in the Mob Tab.
	 */
	public static final String GROUP_LIST = "/images/mob-black.png";
	/**
	 * The relative path to the Icon file to display in the Report Tab.
	 */
	public static final String REPORT = "/images/mob-black.png";
	/**
	 * The relative path to the Icon file to display in the Observation list Tab
	 */
	public static final String OBSERVATION_LIST = "/images/observation-black.png";
	/**
	 * The relative path to the Icon file to display in the Weights list Tab
	 */
	public static final String WEIGHT_LIST = "/images/weighing-black.png";
	/**
	 * The relative path to the Icon file to display in the Reports page Tab
	 */
	public static final String REPORT_PAGE = "/images/report-black.png";
	
	/**
	 * The preferred width of an icon.
	 */
	public static final int ICON_WIDTH = 32;
	/**
	 * The preferred height of an icon.
	 */
	public static final int ICON_HEIGHT = 32;
	
	private JTabbedPane tabbedPane;
	private SidePanel scrollPane;
	private JPanel contentPanel;
	private HomePanel mainPanel;
	private GroupPanel groupPanel;
	private BovinePanel bovinePanel;
	private JoiningPanel joiningPanel;
	private PaddockPanel paddockPanel;
	private MedicinePanel medicinePanel;
	private ChemicalPanel chemicalPanel;
	private LocationPanel locationPanel;
	private FeedPanel feedPanel;
	private ReportPanel reportPanel;
	
	/**
	 * The Current instance of the MainFrame window.
	 */
	private static MainFrame instance=null;
	
	/**
	 * Constructor
	 */
	public MainFrame(){
		instance = this;
		setTitle("Beef Cattle Management - Livestock Solutions");
		setIconImage(getImage(APP_ICON));
		setModalExclusionType(ModalExclusionType.APPLICATION_EXCLUDE);
		setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		setSize(800, 600);
		setLocationRelativeTo(null);
		
		contentPanel=new JPanel();
		contentPanel.setBorder(null);
		setContentPane(contentPanel);
		contentPanel.setLayout(new BorderLayout(0, 0));
		drawTabs();
		
		setJMenuBar(new MenuBar());
	}
	
	/**
	 * Returns the current instance of the MainFrame window.
	 * @return The current instance of the ManiFrame window.
	 */
	public static MainFrame getInstance(){
		return instance;
	}
	
	/**
	 * Place all the tabs into the tab layout
	 */
	public void drawTabs(){
		tabbedPane=new JTabbedPane();
		tabbedPane.addTab("Home",scale(getImageIcon(HOME_LIST),ICON_WIDTH,ICON_HEIGHT), mainPanel=new HomePanel());
		tabbedPane.addTab("Cattle",scale(getImageIcon(CATTLE_LIST),ICON_WIDTH,ICON_HEIGHT), bovinePanel=new BovinePanel());
		tabbedPane.addTab("Mob / Group",scale(getImageIcon(GROUP_LIST),ICON_WIDTH,ICON_HEIGHT),groupPanel=new GroupPanel());
		tabbedPane.addTab("Joinings",scale(getImageIcon(JOINING_LIST),ICON_WIDTH,ICON_HEIGHT), joiningPanel=new JoiningPanel());
		tabbedPane.addTab("Paddock",scale(getImageIcon(PADDOCK_LIST),ICON_WIDTH,ICON_HEIGHT), paddockPanel=new PaddockPanel());
		tabbedPane.addTab("Medicine",scale(getImageIcon(MEDICINE_LIST),ICON_WIDTH,ICON_HEIGHT), medicinePanel=new MedicinePanel());
		tabbedPane.addTab("Chemical",scale(getImageIcon(CHEMICAL_LIST),ICON_WIDTH,ICON_HEIGHT), chemicalPanel=new ChemicalPanel());
		tabbedPane.addTab("Feed",scale(getImageIcon(FEED_LIST),ICON_WIDTH,ICON_HEIGHT), feedPanel=new FeedPanel());
		tabbedPane.addTab("Location",scale(getImageIcon(LOCATION_LIST),ICON_WIDTH,ICON_HEIGHT), locationPanel=new LocationPanel());
		tabbedPane.addTab("Report",scale(getImageIcon(REPORT_PAGE),ICON_WIDTH,ICON_HEIGHT), reportPanel=new ReportPanel());
		tabbedPane.addMouseListener(new MouseListener(){
			@Override public void mouseClicked(MouseEvent e) {}
			@Override public void mousePressed(MouseEvent e) {
				refreshTab();
			}
			@Override public void mouseReleased(MouseEvent e) {}
			@Override public void mouseEntered(MouseEvent e) {}
			@Override public void mouseExited(MouseEvent e) {}
		});

		contentPanel.removeAll();
		contentPanel.add(tabbedPane, BorderLayout.CENTER);
		contentPanel.validate();
		
		mainPanel.displayPanel();
	}
	
	/**
	 * Causes the current tab to be re-drawn
	 */
	public void refreshTab() {
		Component selectedTab = tabbedPane.getSelectedComponent();
		if (selectedTab instanceof TabbedInterface){
			//TODO once Report Panel has been updated, remove this conditional statement.
			if(selectedTab instanceof ReportPanel){
				contentPanel.add(scrollPane = new SidePanel(), BorderLayout.WEST);
			}else if(scrollPane!=null){
				contentPanel.remove(scrollPane);
				scrollPane=null;
			}
			((TabbedInterface)selectedTab).displayPanel();
		}
	}
	
	/**
	 * Main method that starts this system
	 * @param args Any arguments that can be passed to this program (currently none)
	 */
	public static void main(String[] args) {
		try{System.setErr(new Logger(new FileOutputStream(new File(LivestockSolutions.getStorageLocation(),"errorLog.txt"),true),System.err));}catch(FileNotFoundException e){}
		try{UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());}catch (Exception e){}
		EventQueue.invokeLater(new Runnable() {
			@Override
			public void run() {
				try {
					// Go through all UI values and change the font size to 14
					// TODO have this customisable
					Enumeration<Object> keys = UIManager.getDefaults().keys();
					while (keys.hasMoreElements()){
						Object key = keys.nextElement();
						Object value = UIManager.get(key);
						if (value instanceof javax.swing.plaf.FontUIResource){
							UIManager.put(key, new FontUIResource(((FontUIResource)value).deriveFont(14f)));
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
		
		instance = new MainFrame();
		
		if(!saveLoad(false)){
			// Concurrent modification detected;
			if(JOptionPane.showOptionDialog(instance,
				"Another instance of this program may be running, or this program was not properly shutdown last time.\n" +
				"Click \"Continue\" to ignore this message and continue using this program, risking potential data loss or\n"+
				"click \"Quit\" to exit.","Multiple Instances Detected",JOptionPane.YES_NO_OPTION,JOptionPane.ERROR_MESSAGE, null, new String[]{"Continue","Quit"}, "Quit") == JOptionPane.YES_OPTION){
				LivestockSolutions.ignoreLock();
			}else{
				instance.dispose();
				return;
			}
		}
		
		// Update the date format or set it to system default value
		if(LivestockSolutions.getDateFormat()!=null){
			JDatePickerDate.setDateFormat(LivestockSolutions.getDateFormat());
		}else{
			LivestockSolutions.setDateFormat(JDatePickerDate.getDateFormat());
		}
		
		Table.updateColours(
			LivestockSolutions.getColour(LivestockSolutions.HEADER_ORDERED),
			LivestockSolutions.getColour(LivestockSolutions.HEADER),
			LivestockSolutions.getColour(LivestockSolutions.LIST_HOVER),
			LivestockSolutions.getColour(LivestockSolutions.LIST_CLICK),
			LivestockSolutions.getColour(LivestockSolutions.LIST_A1),
			LivestockSolutions.getColour(LivestockSolutions.LIST_A2),
			LivestockSolutions.getColour(LivestockSolutions.LIST_B1),
			LivestockSolutions.getColour(LivestockSolutions.LIST_B2));
		instance.setSelectedTab(instance.getSelectedTab());
		instance.setVisible(true);
		
		// Set window state.
		Object windowState = LivestockSolutions.getProgramSettings("WINDOWMAXAMISED");
		windowState=windowState==null||(Integer)windowState==Frame.ICONIFIED?Frame.NORMAL:windowState;
		instance.setExtendedState((Integer)windowState);
		
		// Resize window.
		Dimension d = (Dimension)LivestockSolutions.getProgramSettings("WINDOWDIMENSION");
		d=d==null?instance.getSize():d;
		instance.setSize(d);
		
		// Re-center the window.
		instance.setLocationRelativeTo(null);
		// Move window.
		Point p = (Point)LivestockSolutions.getProgramSettings("LOCATION");
		p=p==null?instance.getLocation():p;
		instance.setLocation(p);
		
		String v = (String)LivestockSolutions.getProgramSettings("VISIBLETAB");
		if(v!=null){
			for(int x=0; x< instance.tabbedPane.getTabCount();x++){
				if(instance.tabbedPane.getTitleAt(x).trim().toLowerCase().equals(v.trim().toLowerCase())){
					instance.tabbedPane.setSelectedIndex(x);
					long id=(Long)LivestockSolutions.getProgramSettings("VISIBLEOBJECT");
					
					if(id!=0){
						Component c=instance.tabbedPane.getSelectedComponent();
						if(c instanceof TabbedInterface){
							if(c instanceof BovinePanel){
								instance.showBovine(id);
							}else if(c instanceof ChemicalPanel){
								instance.showChemical(id);
							}else if(c instanceof GroupPanel){
								instance.showGroup(id);
							}else if(c instanceof JoiningPanel){
								instance.showJoining(id);
							}else if(c instanceof LocationPanel){
								instance.showLocation(id);
							}else if(c instanceof MedicinePanel){
								instance.showMedicine(id);
							}else if(c instanceof PaddockPanel){
								instance.showPaddock(id);
							}else if(c instanceof ReportPanel){
								instance.showReport((int)id);
							}
						}
					}
					instance.refreshTab();
					break;
				}
			}
		}
	}
	
	/**
	 * Get the Component of the selected tab.
	 * @return The currently selected tab.
	 */
	public Component getSelectedTab(){
		return tabbedPane.getSelectedComponent();
	}
	
	/**
	 * Set the selected tab to the tab given.
	 * @param tab The Component that exists as a tab to set selected.
	 * @return <tt>true</tt> if the component exists as a tab, <tt>false</tt> otherwise.
	 */
	public boolean setSelectedTab(Component tab){
		if(tabbedPane.indexOfComponent(tab)>-1){
			tabbedPane.setSelectedComponent(tab);
			refreshTab();
			return true;
		}
		return false;
	}
	
	/**
	 * Switch to and Show the Bovine details with this particular ID
	 * Providing up to two Bovine, where one is a Male, and the other is Female, will add
	 * them as being the Sire and Dame of this Bovine
	 * ignored along with any Bovine of type Bovine.
	 * @param bovineID The Long internal ID for the Join to show.
	 * @param bovine Bovine of either Bull, Cow or both that will attempt to be set as the Dame and Sire
	 *         of this bovine.
	 * @return <tt>true</tt> if the Bovine with the ID exists and was shown to the user,
	 *         <tt>false</tt> otherwise.
	 */
	public boolean showBovine(long bovineID, Bovine... bovine){
		if(bovinePanel.createBovinePanel(bovineID, bovine)){
			tabbedPane.setSelectedComponent(bovinePanel);
			return true;
		}
		return false;
	}
	
	/**
	 * Switch to and Show the Bovine details with this particular ID
	 * @param id The Long internal ID for the Bovine animal.
	 * @return <tt>true</tt> if the animal with the ID exists and was shown to the user,
	 * <tt>false</tt> otherwise.
	 */
	public boolean showBovine(long id){
		if(bovinePanel.createBovinePanel(id)){
			tabbedPane.setSelectedComponent(bovinePanel);
			return true;
		}
		return false;
	}
	
	/**
	 * Switch to and Show the Mob details with this particular ID
	 * @param id The Long internal ID for the Mob.
	 * @return <tt>true</tt> if the Mob with the ID exists and was shown to the user,
	 * <tt>false</tt> otherwise.
	 */
	public boolean showMob(long id){
		if(groupPanel.createMobPanel(id)){
			tabbedPane.setSelectedComponent(groupPanel);
			return true;
		}
		return false;
	}
	
	/**
	 * Switch to and Show the Group details with this particular ID
	 * @param id The Long internal ID for the Group.
	 * @param bovines The Bovines to add to this Group.
	 * @return <tt>true</tt> if the Group with the ID exists and was shown to the user,
	 * <tt>false</tt> otherwise.
	 */
	public boolean showGroup(long id, Bovine...bovines){
		if(groupPanel.createGroupPanel(id,bovines)){
			tabbedPane.setSelectedComponent(groupPanel);
			return true;
		}
		return false;
	}
	
	/**
	 * Switch to and Show the Group details with this particular ID
	 * @param id The Long internal ID for the Group.
	 * @return <tt>true</tt> if the Group with the ID exists and was shown to the user,
	 * <tt>false</tt> otherwise.
	 */
	public boolean showGroup(long id){
		if(groupPanel.createGroupPanel(id)){
			tabbedPane.setSelectedComponent(groupPanel);
			return true;
		}
		return false;
	}
	
	/**
	 * Switch to and Show the Paddock details with this particular ID
	 * @param id The Long internal ID for the Paddock.
	 * @return <tt>true</tt> if the Paddock with the ID exists and was shown to the user,
	 * <tt>false</tt> otherwise.
	 */
	public boolean showPaddock(long id){
		if(paddockPanel.createPaddockPanel(id)){
			tabbedPane.setSelectedComponent(paddockPanel);
			return true;
		}
		return false;
	}
	
	/**
	 * Switch to and Show the Location details with this particular ID
	 * @param id The Long internal ID for the Location.
	 * @return <tt>true</tt> if the Location with the ID exists and was shown to the user,
	 * <tt>false</tt> otherwise.
	 */
	public boolean showLocation(long id){
		if(locationPanel.createLocationPanel(id)){
			tabbedPane.setSelectedComponent(locationPanel);
			return true;
		}
		return false;
	}
	
	/**
	 * Switch to and Show the Joining details with this particular ID
	 * @param joinID The Long internal ID for the Join to show.
	 * @param mobID The Long internal ID for the Mob that is applying this Joining to.
	 * @return <tt>true</tt> if the Joining with the ID exists and was shown to the user,
	 * <tt>false</tt> otherwise.
	 */
	public boolean showJoining(long joinID, long mobID){
		if(joiningPanel.createJoiningPanel(joinID, mobID)){
			tabbedPane.setSelectedComponent(joiningPanel);
			return true;
		}
		return false;
	}
	
	/**
	 * Switch to and Show the Joining details with this particular ID.
	 * Providing a list of Bovines, If joinID is not '-1' then any Bull type Bovines will be
	 * ignored along with any Bovine of type Bovine.
	 * @param joinID The Long internal ID for the Join to show.
	 * @param bovine Bovine Object to set as either the Bull, or as a member.
	 * @return <tt>true</tt> if the Joining with the ID exists and was shown to the user,
	 * <tt>false</tt> otherwise.
	 */
	public boolean showJoining(long joinID, Bovine... bovine){
		if(joiningPanel.createJoiningPanel(joinID, bovine)){
			tabbedPane.setSelectedComponent(joiningPanel);
			return true;
		}
		return false;
	}
	
	/**
	 * Switch to and Show the Joining details with this particular ID
	 * @param id The Long internal ID for the Joining.
	 * @return <tt>true</tt> if the Joining with the ID exists and was shown to the user,
	 * <tt>false</tt> otherwise.
	 */
	public boolean showJoining(long id){
		if(joiningPanel.createJoiningPanel(id)){
			tabbedPane.setSelectedComponent(joiningPanel);
			return true;
		}
		return false;
	}
	
	/**
	 * Switch to and Show the Medicine details with this particular ID.
	 * @param id The id of the Medicine to show.
	 * @return <tt>true</tt> if the Medicine with the ID exists and was shown to the user,
	 * <tt>false</tt> otherwise.
	 */
	public boolean showMedicine(long id){
		if(medicinePanel.createItemPanel(id)){
			tabbedPane.setSelectedComponent(medicinePanel);
			return true;
		}
		return false;
	}
	
	/**
	 * Switch to and Show the Chemical details with this particular ID.
	 * @param id The id of the Medicine to show.
	 * @return <tt>true</tt> if the Medicine with the ID exists and was shown to the user,
	 * <tt>false</tt> otherwise.
	 */
	public boolean showChemical(long id){
		if(chemicalPanel.createItemPanel(id)){
			tabbedPane.setSelectedComponent(chemicalPanel);
			return true;
		}
		return false;
	}
	
	/**
	 * Switch to and Show the Feed details with this particular ID.
	 * @param id The id of the Feed to show.
	 * @return <tt>true</tt> if the Feed with the ID exists and was shown to the user,
	 * <tt>false</tt> otherwise.
	 */
	public boolean showFeed(long id){
		if(feedPanel.createItemPanel(id)){
			tabbedPane.setSelectedComponent(feedPanel);
			return true;
		}
		return false;
	}
	
	/**
	 * The report to Show the report tab and begin the report generation process.<br>
	 * NOTE: This method does not actually do anything, it would be planned to be used to
	 *       generate reports pre-formed that do not involve any decisions.
	 * @param report The report to generate.
	 * @return <tt>true</tt> always.
	 */
	public boolean showReport(int report){
		reportPanel.displayPanel(report);
		tabbedPane.setSelectedComponent(reportPanel);
		return true;
	}
	
	/**
	 * Switch to and Show the Owner details with this particular ID.
	 * @param id The id of the Owner to show.
	 * @return <tt>true</tt> if the Owner with the ID exists and was shown to the user,
	 * <tt>false</tt> otherwise.
	 */
	public boolean showOwner(long id){
		//TODO stub
		return false;
	}
	
	/**
	 * Conduct a search for a Bovine.
	 * @param searchQuery The String to use to search for any matching Bovines.
	 * @return <tt>true</tt> if search was completed,
	 * <tt>false</tt> otherwise.
	 */
	public boolean doBovineSearch(String searchQuery){
		if(bovinePanel.createDisplaySearchDetails(searchQuery)){
			tabbedPane.setSelectedComponent(bovinePanel);
			return true;
		}
		return false;
	}
		
	
	/**
	 * Clear the entire SidePanel.
	 * @deprecated Old method, instead insert components within the tab.
	 */
	@Deprecated
	public void clearSidePane(){
		scrollPane.clearMenu();
	}
	
	/**
	 * Clear the Top section of the SidePanel.
	 * @deprecated Old method, instead insert components within the tab.
	 */
	@Deprecated
	public void clearTopSidePane(){
		scrollPane.clearTopMenu();
	}
	
	/**
	 * Clear the Centre section of the SidePanel.
	 * @deprecated Old method, instead insert components within the tab.
	 */
	@Deprecated
	public void clearCentreSidePane(){
		scrollPane.clearCentreMenu();
	}
	
	/**
	 * Clear the Bottom section of the SidePanel.
	 * @deprecated Old method, instead insert components within the tab.
	 */
	@Deprecated
	public void clearBottomSidePane(){
		scrollPane.clearBottomMenu();
	}
	
	/**
	 * Add a Component to the top of the SidePanel on the main window.
	 * @param component The Component to add.
	 * @deprecated Old method, instead insert components within the tab.
	 */
	@Deprecated
	public void addComponentTopSidePane(Component... component){
		for(Component c : component){
			scrollPane.add(SidePanel.TOP, c);
		}
		scrollPane.validate();
	}
	
	/**
	 * Add a Component to the top of the SidePanel on the main window.
	 * @param index The position in which to add the Component.
	 * @param component The Component to add.
	 * @deprecated Old method, instead insert components within the tab.
	 */
	@Deprecated
	public void addComponentTopSidePane(int index, Component component){
		scrollPane.add(SidePanel.TOP, component, index);
		scrollPane.validate();
	}
	
	/**
	 * Add a Component to the middle of the SidePanel on the main window.
	 * @param component The Component to add.
	 * @deprecated Old method, instead insert components within the tab.
	 */
	@Deprecated
	public void addComponentCentreSidePane(Component... component){
		for(Component c : component){
			scrollPane.add(SidePanel.CENTRE, c);
		}
		scrollPane.validate();
	}
	
	/**
	 * Add a Component to the middle of the SidePanel on the main window.
	 * @param index The position in which to add the Component.
	 * @param component The Component to add.
	 * @deprecated Old method, instead insert components within the tab.
	 */
	@Deprecated
	public void addComponentCentreSidePane(int index, Component component){
		scrollPane.add(SidePanel.CENTRE, component, index);
		scrollPane.validate();
	}
	
	/**
	 * Add a Component to the bottom of the SidePanel on the main window.
	 * @param component The Component to add.
	 * @deprecated Old method, instead insert components within the tab.
	 */
	@Deprecated
	public void addComponentBottomSidePane(Component... component){
		for(Component c : component){
			scrollPane.add(SidePanel.BOTTOM, c);
		}
		scrollPane.validate();
	}
	
	/**
	 * Add a Component to the bottom of the SidePanel on the main window.
	 * @param index The position in which to add the Component.
	 * @param component The Component to add.
	 * @deprecated Old method, instead insert components within the tab.
	 */
	@Deprecated
	public void addComponentBottomSidePane(int index, Component component){
		scrollPane.add(SidePanel.BOTTOM, component, index);
		scrollPane.validate();
	}
	
	@Override
	public void dispose(){
		// Save Data
		saveLoad(true);
		LivestockSolutions.close=true;
		super.dispose();
	}

	private static boolean result=true;
	private static boolean running = true;
	/**
	 * Display progress bar for a save and load operations.
	 * @param save Perform a save if <tt>true</tt>, otherwise load.
	 * @return <tt>true</tt> if operation was successful. <tt>false</tt> otherwise.
	 */
	public static boolean saveLoad(final boolean save){
		final String title=save?"Saving...":"Loading...";
		
		final JFrame progress= new JFrame(title);
		final JProgressBar progressBar = new JProgressBar();
		final JLabel progressLabel = new JLabel(title);
		
		final Thread t=new Thread() {
			public void run(){
				int percent = 0;
				String message="";
				String ma="";
				running=true;
		    	while(running && percent>=0){
		    		if(percent>0&&progressBar.isIndeterminate()){
		    			progressBar.setIndeterminate(false);
		    		}
		    		percent=LivestockSolutions.getProgress();
		    		percent=percent<0||percent>100?100:percent;
					progress.setTitle(title+" ("+percent+"%)");
		            progressBar.setValue(percent);
		            ma=LivestockSolutions.getMessage();
		            message=ma.equals("")?message:ma;
		            if(!message.equals("")){
		            	ma=message+" ("+percent+"%)";
		            	if(!progressLabel.getText().equals(ma)){
				            progressLabel.setText(ma);
		            	}
		            }
		            try{
		    			sleep(5);
		    		}catch(Exception e){}
		    	}
		    	LivestockSolutions.resetProgress();
			}
		};
		t.start();
		
		progress.setLayout(new BorderLayout());
		progressBar.setBorder(new EmptyBorder(5,5,0,5));
		progressLabel.setBorder(new EmptyBorder(0,5,5,5));
		progress.add(progressLabel, BorderLayout.NORTH);
		progress.add(progressBar, BorderLayout.SOUTH);
		if(!save){
			progress.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		}
		
		try{ //TODO determine source of IndexOutOfBoundsException in progress.setVisible(true); line
			progress.setIconImage(getImage(APP_ICON));
			progress.pack();
			progress.setSize(400,progress.getHeight());
			progress.setLocationRelativeTo(null);
			progressBar.setValue(0);
			progressBar.setIndeterminate(true);
			progress.setVisible(true);
			progress.setAlwaysOnTop(true);
			progress.setResizable(false);
		}catch(Exception e){
			e.printStackTrace();
		}
		
		if(save){
			if(!LivestockSolutions.isLocked()){
				// Add window data.
				Component c=instance.tabbedPane.getSelectedComponent();
				long id=0;
				if(c instanceof TabbedInterface){
					id=((TabbedInterface)c).getID();
				}
				LivestockSolutions.setProgramSettings("VISIBLEOBJECT",id);
				LivestockSolutions.setProgramSettings("VISIBLETAB",instance.tabbedPane.getTitleAt(instance.tabbedPane.getSelectedIndex()));
				LivestockSolutions.setProgramSettings("WINDOWMAXIMISED",instance.getExtendedState());
				if(instance.getExtendedState()==Frame.MAXIMIZED_BOTH||instance.getExtendedState()==Frame.ICONIFIED){
					instance.setExtendedState(Frame.NORMAL);
				}
				LivestockSolutions.setProgramSettings("WINDOWDIMENSION",instance.getSize());
				LivestockSolutions.setProgramSettings("LOCATION",instance.getLocation());
				instance.setVisible(false);
				// Save
				result=LivestockSolutions.save();
			}
		}else{
			result=LivestockSolutions.initilise();
		}
		running = false;

		
		try {
			t.join();
		} catch (InterruptedException e) {}
		progress.dispose();
		return result;
	}
	
	/**
	 * Get the Image at the given location
	 * @param path The relative path to the Image.
	 * @return The Image at the given path, or null if it does not exist
	 */
	public static Image getImage(String path){
		URL o = null;
		try{
			o = path.getClass().getResource(path);
		}catch(NullPointerException e){e.printStackTrace();}
		if(o!=null){
			return getImageIcon(path).getImage();
		}
		return null;
	}
	
	/**
	 * @param icon The Icon to resize.
	 * @param width The new width of the ImageIcon.
	 * @param height The new height of the ImageIcon.
	 * @return A new resized ImageIcon.
	 */
	public static ImageIcon scale(ImageIcon icon, int width, int height){
		try {
			return new ImageIcon(icon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH)); 
		}catch(Exception e){}
		return null;
	}
	
	/**
	 * Get the ImageIcon at the given location
	 * @param path The relative path to the Image.
	 * @return The ImageIcon at the given path, or null if it does not exist
	 */
	public static ImageIcon getImageIcon(String path){
		URL o = path.getClass().getResource(path);
		if(o!=null){
			return new ImageIcon(o);
		}
		return null;
	}
	
	/**
	 * Create the Menu for the Main window.
	 *
	 */
	public class MenuBar extends JMenuBar {
		private static final long serialVersionUID = 1L;
		
		/**
		 * Constructor
		 */
		public MenuBar(){
			JMenu fileMenu = new JMenu("File");
			JMenuItem sync = new JMenuItem("Sync Android Device");
			sync.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent e) {
					SynchronizeFrame sf = new SynchronizeFrame();
					sf.setVisible(true);
				}
			});
			
			JMenuItem importWeightData = new JMenuItem("Import Data From CSV");
			importWeightData.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent e) {
					ImportWeightDataFrame aFrame = new ImportWeightDataFrame();
					aFrame.start();
				}
			});
			
			JMenuItem close = new JMenuItem("Close");
			close.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent e) {
					MainFrame.getInstance().dispose();
				}
			});
			
			fileMenu.add(sync);
			fileMenu.add(importWeightData);
			fileMenu.add(new JSeparator());
			fileMenu.add(close);
			add(fileMenu);
			
			JMenu settingMenu = new JMenu("Settings");
			JMenuItem backup = new JMenuItem("Backup Now");
			backup.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent e) {
					BackupFrame backupFrame = new BackupFrame();
					backupFrame.start();
				}
			});
			
			JMenuItem restore = new JMenuItem("Restore Backup");
			restore.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent e) {
					BackupFrame backupFrame = new BackupFrame();
					backupFrame.setBackup(false);
					backupFrame.start();
				}
			});
			
			JMenuItem archive = new JMenuItem("Archive");
			archive.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent e) {
					ArchiveFrame archiveFrame = new ArchiveFrame();
					archiveFrame.start();
				}
			});
			
			JMenuItem settings = new JMenuItem("Settings");
			settings.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent e) {
					SettingsFrame settingsFrame = new SettingsFrame();
					settingsFrame.setVisible(true);
				}
			});
			settingMenu.add(backup);
			settingMenu.add(restore);
			settingMenu.add(new JSeparator());
			settingMenu.add(archive);
			settingMenu.add(new JSeparator());
			settingMenu.add(settings);
			add(settingMenu);

			JMenu helpMenu = new JMenu("Help");
			JMenuItem help = new JMenuItem("Help");
			help.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent e) {
					HelpFrame helpFrame = new HelpFrame();
					helpFrame.setVisible(true);
				}
			});
			
			JMenuItem about = new JMenuItem("About");
			about.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent e) {
					AboutFrame aboutFrame = new AboutFrame();
					aboutFrame.setVisible(true);
				}
			});
			
			helpMenu.add(help);
			helpMenu.add(new JSeparator());
			helpMenu.add(about);
			add(helpMenu);
		}
	}
}
